package com.wssnail.redis.aspect;


import com.wssnail.redis.annotation.SnailRedisLock;
import com.wssnail.redis.lock.DistributeLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;

/**
 * @Author: 熟透的蜗牛
 * @CreateTime: 2022-07-14 09:24
 * @Description: 分布式锁切面
 * @Version: 1.0
 */
@Slf4j
@Aspect
public class SnailRedisLockAspect {

    @Autowired
    private DistributeLock distributeLock;

    public SnailRedisLockAspect(DistributeLock distributeLock){
        this.distributeLock=distributeLock;
    }

    @Around(value = "@annotation(com.wssnail.redis.annotation.SnailRedisLock)")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取注解上的方法
        Method method = getMethod(joinPoint);
        //获取方法上的注解
        SnailRedisLock annotation = method.getDeclaredAnnotation(SnailRedisLock.class);
        //获取注解上的参数
        String lockKey = annotation.lockKey();
        String value = annotation.value();
        long expireTime = annotation.expireTime();
        try {
            boolean tryLock = distributeLock.tryLock(lockKey, value, expireTime);
            if (tryLock) {
                joinPoint.proceed();
            } else {
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            distributeLock.releaseLock(lockKey, value);
        }
    }

    /*
     * @description:获取切面上的方法
     * @Author: 熟透的蜗牛
     * @date: 2022/7/14 9:31
     * @param joinPoint
     * @return:
     * @return: java.lang.reflect.Method
     **/
    private Method getMethod(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        //获取方法签名
        String methodName = joinPoint.getSignature().getName();
        // 获取目标对象
        Class<? extends Object> targetClass = joinPoint.getTarget().getClass();
        // 获取目标对象类型
        Class[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        // 获取目标对象方法
        Method objMethod = targetClass.getDeclaredMethod(methodName, par);
        return objMethod;
    }
}
